#include "share/std_err.h"
#include "share/unios.h"
#include "ad9172.h"

/**
 * AD9172 的寄存器为 24 位，高位在前
 * bit[23:23]: R(1)/W(0) 标志
 * bit[22:8 ]: 15 位寄存器地址
 * bit[7 :0 ]: 8 位寄存器值
 */

static std_err_t _regw(unidrv_ad9172_t *dev, uint16_t regaddr, uint8_t regval) {
	uint8_t tx[3], rx[3];
    // 注意：big-endian(大端在前)
    tx[0] = (regaddr >> 8 ) & 0x7F;
    tx[1] = (regaddr      ) & 0xFF;
    tx[2] = regval;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

static uint8_t _regr(unidrv_ad9172_t *dev, uint16_t regaddr) {
	uint8_t tx[3], rx[3];
    // 注意：big-endian(大端在前)
    tx[0] = ((regaddr >> 8) & 0xFF) | 0x80; // R(1)/W(0) 标志设置为 1 表示读寄存器
    tx[1] = regaddr & 0xFF;
    tx[2] = 0xFF;
    
    dev->nss(0); //{{{
    mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return rx[2];
}

static std_err_t _spi_reg_write(unidrv_ad9172_t *dev, uint32_t regval) {
	uint8_t tx[3], rx[3];
    // 注意：只发低 24 位，并且要 big-endian(大端在前)
    tx[0] = (regval >> 16) & 0x7F;
    tx[1] = (regval >> 8 ) & 0xFF;
    tx[2] = (regval      ) & 0xFF;
    
    dev->nss(0); //{{{
    std_err_t err = mcu_spi_trx(dev->spi, tx, rx, 3, NULL);
    dev->nss(1); //}}}
    return err;
}

std_err_t unidrv_ad9172_init(unidrv_ad9172_t *dev, uint32_t *regs1, uint32_t *regs3, uint32_t *regs4, uint32_t *regs5, uint32_t *regs6, uint32_t *regscal) {
    if(!dev || !dev->spi || !dev->nss || !dev->rstn_out || !dev->txen0_out || !dev->txen1_out || !regs1 || !regs3 || !regs4 || !regs5 || !regs6 || !regscal) return STD_ERR_INVALID_ARG;
    std_err_t err;
    uint32_t ret;
    
    // RSTN 拉低 -> 拉高，实现对 AD9172 的复位控制
    dev->rstn_out(0); unios_us_delay(1000); dev->rstn_out(1); unios_us_delay(10000);
    dev->txen0_out(1); dev->txen1_out(1); unios_us_delay(10000);
    _regw(dev, 0x000, 0x3C); // SDOACTIVE=1, ADDRINC=1, LSBFIRST=0, SOFTRESET=0
    //_regw(dev, 0x000, 0xBD); unios_us_delay(10000); // SDOACTIVE=1, ADDRINC=1, LSBFIRST=0, SOFTRESET=1
    _regw(dev, 0x001, 0x80); // Perform single transfers, Disable CS stalling
    
    // 检查芯片类型
    if(_regr(dev, 0x003) != 0x04) {
        return STD_ERR_INVALID_ID;
    }
    
    // 检查芯片PID
    uint16_t pid = _regr(dev, 0x004) | (_regr(dev, 0x005) << 8);
    //if(pid != 0x9172) return STD_ERR_INVALID_ID;

	for(int i=0; regs1[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regs1[i]);
		unios_us_delay(1000);
	}
	unios_us_delay(100000);

	for(int i=0; regs3[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regs3[i]);
		unios_us_delay(1000);
	}
	unios_us_delay(100000);

    // Ensure DLL is locked by reading
	unios_wait_ms_while(ret, 1000, (_regr(dev, 0x0C3) & 0x01));
    if(ret == 0) return STD_ERR_TIMEOUT;

	for(int i=0; regscal[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regscal[i]);
		unios_us_delay(1000);
	}
	unios_us_delay(100000);
    
	unios_wait_ms_until(ret, 1000, (_regr(dev, 0x052) & 0x01));
    if(ret == 0) return STD_ERR_TIMEOUT;

    _spi_reg_write(dev, 0x008103);
	unios_us_delay(100000);

	for(int i=0; regs4[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regs4[i]);
		unios_us_delay(1000);
	}
	unios_us_delay(100000);

	for(int i=0; regs5[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regs5[i]);
		unios_us_delay(1000);
	}
    
    // 等待 PLL 锁定
	unios_wait_ms_until(ret, 1000, (_regr(dev, 0x281) & 0x01));
    if(ret == 0) return STD_ERR_TIMEOUT;

	for(int i=0; regs6[i] != AD9172_REG_END; i++) {
		_spi_reg_write(dev, regs6[i]);
		unios_us_delay(1000);
	}
	unios_us_delay(100000);

    // AD9172 对应的 JESD 接口初始化
    if(dev->jesd_init) {
        err = dev->jesd_init();
        if(err) return err;
    }
    
	return STD_ERR_OK;
}
